package com.sky.service.impl;

import com.aliyun.oss.common.utils.StringUtils;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.sky.dto.GoodsSalesDTO;
import com.sky.entity.Orders;
import com.sky.mapper.OrderMapper;
import com.sky.service.ReportService;
import com.sky.service.WorkspaceService;
import com.sky.vo.*;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.naming.Context;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.LongStream;

@Service
public class ReportServiceImpl implements ReportService {

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private WorkspaceService workspaceService;

    @Override
    public TurnoverReportVO turnoverReport(LocalDate begin, LocalDate end) {
        List<LocalDate> localDates = this.getDateList(begin, end);
        Map paramsMap = new HashMap();
        paramsMap.put("beginDate", begin);
        paramsMap.put("endDate", end);
        paramsMap.put("status", Orders.COMPLETED);
        List<Map> turnoverMapList = this.orderMapper.sumAmountByParamsWithGroupBy(paramsMap);
        Map<String, BigDecimal> turnoverMap = turnoverMapList.stream().collect(Collectors.toMap(t ->
                (String) t.get("date"), t -> (BigDecimal) t.get("amount")));
        List<BigDecimal> amountList = new ArrayList<>(localDates.size());
        for (LocalDate date : localDates) {
            BigDecimal amount = turnoverMap.getOrDefault(date.toString(), BigDecimal.valueOf(0, 0));
            amountList.add(amount);
        }
        String dateListStr = StringUtils.join(localDates.toString(), ",");
        dateListStr = localDates.stream().map(date -> date.toString()).collect(Collectors.joining(","));
        String turnStr = amountList.stream().map(a -> a.toString()).collect(Collectors.joining(","));
        return TurnoverReportVO.builder().dateList(dateListStr).turnoverList(turnStr).build();
    }

    @Override//用户查询
    public UserReportVO userReport(LocalDate begin, LocalDate end) {
        List<LocalDate> dateList = this.getDateList(begin, end);
        List<Integer> newUserList = new ArrayList<>();//新增的用户
        List<Integer> totalUserList = new ArrayList<>();//当天用户
        Map pMap = new HashMap();
        pMap.put("begin", begin);
        pMap.put("end", end);
        List<Map> newUserMapList = this.orderMapper.countUserByParamWithGroupby(pMap);
        Map<String, Integer> newUserMap = newUserMapList.stream().collect(
                Collectors.toMap(u -> (String) u.get("date"), u -> Integer.valueOf(u.get("num").toString())));
        pMap.put("date", begin.minusDays(1));
        pMap.put("newUserFlag", false);
        Integer totalUserCount = this.orderMapper.countUserByParams(pMap);
        for (LocalDate date : dateList) {
            //获取每日新增数
            Integer newUserCount = newUserMap.getOrDefault(date.toString(), 0);
            //获取截止当天用户总数
            totalUserCount += newUserCount;
            //分别放入各自的集合中
            newUserList.add(newUserCount);
            totalUserList.add(totalUserCount);
        }
        //拼接出参的三个字符串，封装vo返回
        String dateListStr = dateList.stream().map(date -> date.toString()).collect(Collectors.joining(","));
        String newUserListStr = newUserList.stream().map(num -> num.toString()).collect(Collectors.joining(","));
        String totalUserListStr = totalUserList.stream().map(num -> num.toString()).collect(Collectors.joining(","));
        return UserReportVO.builder().dateList(dateListStr).newUserList(newUserListStr).totalUserList(totalUserListStr).build();
    }

    @Override//订单统计
    public OrderReportVO ordersStatus(LocalDate begin, LocalDate end) {
        List<LocalDate> dateList = this.getDateList(begin, end);
        Map pMap = new HashMap();
        pMap.put("beginDate", begin);
        pMap.put("endDate", end);
        List<Map> orderCountMapList = this.orderMapper.orderCountByParamsWithGroupby(pMap);//查找订单
        Map<String, Long> orderCountMap = orderCountMapList.stream().collect(
                Collectors.toMap(o -> (String) o.get("date"), o -> (Long) o.get("num")));//将List中的元素转换为一个Map对象
        //循环日期列表，组装【订单数集合】、【有效订单数集合】
        pMap.put("status", Orders.COMPLETED);
        List<Map> validOrderCountMapList = this.orderMapper.orderCountByParamsWithGroupby(pMap);
        Map<String, Long> validOrderCountMap = validOrderCountMapList.stream().collect(
                Collectors.toMap(o -> (String) o.get("date"), o -> (Long) o.get("num")));
        List<Long> orderCountList = new ArrayList<>();
        List<Long> validOrderCountList = new ArrayList<>();
        for (LocalDate date : dateList) {
            //从Map中获取对应日期的订单总数、有效订单数
            Long ordercount = orderCountMap.getOrDefault(date.toString(), Long.valueOf(0));
            Long validOrderCount = validOrderCountMap.getOrDefault(date.toString(), Long.valueOf(0));
            //将订单总数和有效订单数添加至 对应的集合中
            orderCountList.add(ordercount);
            validOrderCountList.add(validOrderCount);
        }
        //计算订单总数、有效订单数、订单完成率
        Long totalOrderCount = orderCountList.stream().mapToLong(o -> o).sum();
        totalOrderCount = orderCountList.stream().flatMapToLong(o -> LongStream.of(o)).sum();
        totalOrderCount = orderCountList.stream().reduce(Long::sum).get();
        Long validOrderCount = validOrderCountList.stream().mapToLong(o -> o).sum();
        Double orderCompletionRate = totalOrderCount == 0 ? 0.0 : validOrderCount.doubleValue() / totalOrderCount;
        return OrderReportVO.builder().dateList(dateList.stream().map(date -> date.toString()).collect(Collectors.joining(",")))
                .orderCountList(orderCountList.stream().map(c -> c.toString()).collect(Collectors.joining(",")))
                .validOrderCountList(validOrderCountList.stream().map(c -> c.toString()).collect(Collectors.joining(",")))
                .totalOrderCount(Integer.valueOf(totalOrderCount.toString()))
                .validOrderCount(Integer.valueOf(validOrderCount.toString()))
                .orderCompletionRate(orderCompletionRate)
                .build();
    }


    /**
     * 商品销量统计（前10）
     *
     * @param begin 开始日期
     * @param end   结束日期
     * @return
     */
    @Override
    public SalesTop10ReportVO top10(LocalDate begin, LocalDate end) {
        //1、统计查询指定日期范围内的菜品、套餐销售情况（菜品名称、销量）
        Map paramsMap = new HashMap();
        paramsMap.put("beginDate", begin);
        paramsMap.put("endDate", end);
        paramsMap.put("status", Orders.COMPLETED);
        List<GoodsSalesDTO> top10List = this.orderMapper.salesTop10ByParams(paramsMap);

        //2、组装数据，封装VO
        String nameListStr = top10List.stream().map(good -> good.getName()).collect(Collectors.joining(","));
        String numberListStr = top10List.stream().map(good -> good.getNumber().toString()).collect(Collectors.joining(","));
        return SalesTop10ReportVO.builder().nameList(nameListStr).numberList(numberListStr).build();
    }

    @Override
    public void export(HttpServletResponse response) throws IOException, InvalidFormatException {

    }

//导出三十天数据
//    @Override
//    public void export(HttpServletResponse response) throws IOException, InvalidFormatException {
//        //1、从数据库查询近30天的运营数据
//        LocalDate beginDate = LocalDate.now().minusDays(30);
//        LocalDate endDate = LocalDate.now().minusDays(1);
//        BusinessDataVO businessData = workspaceService.getBusinessData(LocalDateTime.of(beginDate, LocalTime.MIN), LocalDateTime.of(endDate, LocalTime.MAX));
//        //2、运用POI将数据写入excel
//        exportStyle3(response, beginDate, endDate, businessData);
//    }

    /**
     * 使用org.jxls进行基于excel模板的导出（模板根据批注读取配置）  poi  版本不能低于4.0

     * @throws IOException
     */
//    private void exportStyle3(HttpServletResponse response, LocalDate startDate, LocalDate endDate, BusinessDataVO businessData) throws IOException {
//        InputStream in = this.getClass().getClassLoader().getResourceAsStream("template/运营数据报表模板3.xlsx");
//        List<LocalDate> dateList = this.getDateList(startDate, endDate);
//        List<BusinessDataVO> voList = new ArrayList<>();
//        for (LocalDate date : dateList) {
//            BusinessDataVO businessDataVO = this.workspaceService.getBusinessData(LocalDateTime.of(date, LocalTime.MIN), LocalDateTime.of(date, LocalTime.MAX));
//            businessDataVO.setDate(date.toString());
//            voList.add(businessDataVO);
//        }
//        businessData.setDate("时间：" + startDate + "至" + endDate);
//        Context context = new Context();
//        context.putVar("dataList", voList);
//        context.putVar("bd", businessData);
//
//        //5、写入到浏览器，关闭流
//        response.setContentType("application/octet-stream");  //非必须
//        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("运营数据报表1.xlsx", "UTF-8"));  //非必须
//        JxlsHelper.getInstance().processTemplate(in, new BufferedOutputStream(response.getOutputStream()), context);
//    }

//    /**
//     * 使用net.sf.jxls.jxls-core进行基于excel模板的导出(poi 版本不能高于4.0)
//     *
//     * @param response
//     * @param startDate
//     * @param endDate
//     * @param businessData
//     * @return
//     * @throws InvalidFormatException
//     */
//    private void exportStyle2(HttpServletResponse response, LocalDate startDate, LocalDate endDate, BusinessDataVO businessData) throws InvalidFormatException, IOException {
//        //1、准备数据
//        InputStream in = this.getClass().getClassLoader().getResourceAsStream("template/运营数据报表模板2.xlsx");
//        List<LocalDate> dateList = this.getDateList(startDate, endDate);
//
//        //1.1、准备明细数据List
//        List<BusinessDataVO> voList = new ArrayList<>();
//        for (LocalDate date : dateList) {
//            BusinessDataVO businessDataVO = this.workspaceService.getBusinessData(LocalDateTime.of(date, LocalTime.MIN), LocalDateTime.of(date, LocalTime.MAX));
//            businessDataVO.setDate(date.toString());
//            voList.add(businessDataVO);
//        }
//
//        //使用net.sf.jxls.jxls-core进行基于excel模板的导出（模板根据表达式读取配置） poi 版本不能高于4.0
//        Map<String, Object> map = new HashMap<>();
//        map.put("dataList", voList);
//        map.put("bd", businessData);
//
//        Workbook excel = new XLSTransformer().transformXLS(in, map);
//        excel.write(response.getOutputStream());
//    }
//
//    /**
//     * 利用原生POI进行excel导出
//     * @param response     响应对象
//     * @param beginDate    开始日期
//     * @param endDate      结束日期
//     * @param businessData 日期范围内的运营数据
//     * @throws IOException
//     */
//    private void exportStyle1(HttpServletResponse response, LocalDate beginDate, LocalDate endDate, BusinessDataVO businessData) throws IOException {
//        InputStream in = this.getClass().getClassLoader().getResourceAsStream("template/运营数据报表模板.xlsx");
//        XSSFWorkbook workbook = new XSSFWorkbook(in);
//
//        XSSFSheet sheet = workbook.getSheetAt(0);
//        //设置日期
//        sheet.getRow(1).getCell(1).setCellValue("时间：" + beginDate + "至" + endDate);
//        //设置概览数据
//        sheet.getRow(3).getCell(2).setCellValue(businessData.getTurnover());
//        sheet.getRow(3).getCell(4).setCellValue(businessData.getOrderCompletionRate());
//        sheet.getRow(3).getCell(6).setCellValue(businessData.getNewUsers());
//
//        sheet.getRow(4).getCell(2).setCellValue(businessData.getValidOrderCount());
//        sheet.getRow(4).getCell(4).setCellValue(businessData.getUnitPrice());
//
//        //设置明细数据
//        List<LocalDate> dateList = this.getDateList(beginDate, endDate);
//        int rownum = 0;
//        for (LocalDate date : dateList) {
//            businessData = workspaceService.getBusinessData(LocalDateTime.of(date, LocalTime.MIN), LocalDateTime.of(date, LocalTime.MAX));
//            XSSFRow row = sheet.getRow(7 + rownum++);
//            row.getCell(1).setCellValue(date.toString());
//            row.getCell(2).setCellValue(businessData.getTurnover());
//            row.getCell(3).setCellValue(businessData.getValidOrderCount());
//            row.getCell(4).setCellValue(businessData.getOrderCompletionRate());
//            row.getCell(5).setCellValue(businessData.getUnitPrice());
//            row.getCell(6).setCellValue(businessData.getNewUsers());
//        }
//
//        //3、将excel通过输出流下载至客户端浏览器
//        workbook.write(response.getOutputStream());
//        in.close();
//        workbook.close();
//    }

    //将起始日期begin添加到dateList中。
//接下来，使用一个循环，判断begin日期是否与结束日期end相等。不相等则将begin日期加一天，并将其添加到dateList中。循环会一直执行，直到begin日期与end日期相等为止。
//最后，返回生成的dateList列表，其中包含了指定日期范围内的所有日期。
    private List<LocalDate> getDateList(LocalDate begin, LocalDate end) {
        List<LocalDate> dateList = new ArrayList<>();
        dateList.add(begin);
        while (!begin.isEqual(end)) {
            begin = begin.plusDays(1);
            dateList.add(begin);
        }
        return dateList;
    }

}
